package com.abocode.aichat.server.endpoint;

import com.abocode.aichat.server.context.ServerRuntimeContext;
import com.abocode.aichat.server.modules.Module;
import com.abocode.aichat.server.context.ServerRuntimeContext;
import com.abocode.aichat.server.modules.Module;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.List;

/**
 * Created by abocode
 */
public abstract class ServerEndpoint implements Endpoint {
    protected static Log log = LogFactory.getLog(ServerEndpoint.class);
    private String name;
    private int parentSize;
    private int childSize;
    private int port;
    private String domain;
//    private Worker worker;
    private ServerRuntimeContext serverRuntimeContext;


//    public Worker getWorker() {
//        return worker;
//    }
//
//    public void setWorker(Worker worker) {
//        this.worker = worker;
//        getServerRuntimeContext().setWorker(worker);
//        worker.setServerRuntimeContext(getServerRuntimeContext());
//    }

    public ServerRuntimeContext getServerRuntimeContext() {
        return serverRuntimeContext;
    }

    public void setServerRuntimeContext(ServerRuntimeContext serverRuntimeContext) {
        this.serverRuntimeContext = serverRuntimeContext;
    }

    private List<Module> modules;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDomain() {
        return domain;
    }

    public void setDomain(String domain) {
        this.domain = domain;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public int getParentSize() {
        return parentSize;
    }

    public void setParentSize(int parentSize) {
        this.parentSize = parentSize;
    }

    public int getChildSize() {
        return childSize;
    }

    public void setChildSize(int childSize) {
        this.childSize = childSize;
    }


    public List<Module> getModules() {
        return modules;
    }

    public void setModules(List<Module> modules) {
        this.modules = modules;
    }

    private EventLoopGroup parent = new NioEventLoopGroup(parentSize);

    private EventLoopGroup child = new NioEventLoopGroup(childSize);

    private ChannelFuture channelFuture = null;

    @Override
    public void shutdown() {
        try {
            child.shutdownGracefully();
            parent.shutdownGracefully();
            channelFuture.channel().close().sync();
//            serverRuntimeContext.getEndpointRegistry().unregister(this);
        } catch (InterruptedException e) {
            if (log.isDebugEnabled()) {
                log.debug("shutdown error", e);
            }
        }
    }

    protected void init() {
        if (serverRuntimeContext == null) {
            throw new NullPointerException("serverRuntimeContext is null");
        }
//        serverRuntimeContext.getEndpointRegistry().register(this);
        serverRuntimeContext.setDomain(getDomain());
        serverRuntimeContext.setName(getName());
        for (Module module : modules) {
            serverRuntimeContext.getWorker().addModule(module);
        }
    }

    @Override
    public void start() {
        init();
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(parent, child);
        bootstrap.childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS,10);
        bootstrap.childOption(ChannelOption.TCP_NODELAY,true);
        bootstrap.channel(NioServerSocketChannel.class);
        bootstrap.childHandler(channelHandler());
//        option(bootstrap);
        try {
            channelFuture = bootstrap.bind(port).sync();
        } catch (InterruptedException e) {
            if (log.isDebugEnabled()) {
                log.debug("start error", e);
            }
        }
    }

//    @Override
//    public ChannelHandler channelHandler() {
//        return new ChannelHandlerRegister(getServerRuntimeContext(), getWorker());
//    }

}
